"""
负责'分析原图信息并显示进度'的一组方法
"""
import os, threading, queue
import tkinter as tk
from tkinter import ttk, messagebox
from pathlib import Path
from PIL import Image, ExifTags                                               # 部分函数里用到了
from utils_image import safe_open_image, load_raw_image, extract_raw_thumbnail # 若函数内部调用

class AnalysisMixin:
    def analyze_images(self, image_paths, base_path=None):
        """分析多个图片的DPI和尺寸信息，并考虑EXIF方向

        Args:
            image_paths: 图片路径列表
            base_path: 基础路径，用于计算相对路径（可选）
        """
        self.all_images_info = []
        has_raw_files = False

        # 检查是否包含RAW文件
        raw_files = []
        normal_files = []
        for path in image_paths:
            if self.is_raw_file(path):
                has_raw_files = True
                raw_files.append(path)
            else:
                normal_files.append(path)

        # 如果包含RAW文件且数量较多，使用异步加载
        if has_raw_files and len(raw_files) > 3:
            self.analyze_images_async(image_paths, has_raw_files)
            return

        # 普通处理流程（少量文件或无RAW文件）
        for path in image_paths:
            try:
                # 在普通分析中也使用预览模式以提高速度
                with self.open_image_file(path, preview_mode=True) as img:
                    dpi = img.info.get('dpi', (72, 72))[0]

                    # 获取正确的宽度和高度，考虑EXIF方向
                    width, height = self.get_oriented_size(img)

                    # 计算相对路径（如果提供了基础路径）
                    relative_path = None
                    if base_path:
                        try:
                            path_obj = Path(path)
                            base_path_obj = Path(base_path)
                            relative_path = path_obj.relative_to(base_path_obj)
                        except ValueError:
                            # 如果无法计算相对路径，则使用None
                            relative_path = None

                    self.all_images_info.append({
                        'path': path,
                        'relative_path': relative_path,
                        'dpi': dpi,
                        'width': width,
                        'height': height
                    })
            except Exception as e:
                print(f"无法分析图片 {path}: {e}")
                # 跳过无法处理的文件，继续处理其他文件

        # 如果包含RAW文件，禁用"保持原格式"选项
        self.update_format_options_for_raw(has_raw_files)

    def analyze_images_async(self, image_paths, has_raw_files):
        """异步分析大量图片，特别是RAW文件"""
        # 先禁用"保持原格式"选项
        self.update_format_options_for_raw(has_raw_files)

        # 显示加载提示
        self.show_loading_dialog(len(image_paths))

        # 启动后台线程进行分析
        self.analysis_thread = threading.Thread(
            target=self._analyze_images_worker,
            args=(image_paths,),
            daemon=True
        )
        self.analysis_thread.start()

        # 定期检查分析进度
        self.check_analysis_progress()

    def show_loading_dialog(self, total_files):
        """显示加载进度对话框"""
        self.loading_window = tk.Toplevel(self.root)
        self.loading_window.title("正在分析图片...")
        self.loading_window.geometry("400x150")
        self.loading_window.transient(self.root)
        self.loading_window.grab_set()

        # 居中显示
        self.loading_window.geometry("+%d+%d" % (
            self.root.winfo_rootx() + 50,
            self.root.winfo_rooty() + 50
        ))

        # 进度信息
        self.loading_label = ttk.Label(
            self.loading_window,
            text=f"正在分析 {total_files} 个文件...\n这可能需要一些时间，请耐心等待",
            font=("Arial", 10)
        )
        self.loading_label.pack(pady=20)

        # 进度条
        self.loading_progress = ttk.Progressbar(
            self.loading_window,
            mode='determinate',
            maximum=total_files
        )
        self.loading_progress.pack(fill=tk.X, padx=20, pady=10)

        # 当前处理文件显示
        self.current_file_label = ttk.Label(
            self.loading_window,
            text="准备开始...",
            font=("Arial", 8)
        )
        self.current_file_label.pack(pady=5)

        # 取消按钮
        self.cancel_analysis_btn = ttk.Button(
            self.loading_window,
            text="取消分析",
            command=self.cancel_analysis,
            bootstyle="warning"
        )
        self.cancel_analysis_btn.pack(pady=10)

        # 初始化分析状态
        self.analysis_complete = False
        self.analysis_progress = 0
        self.current_analyzing_file = ""
        self.analysis_cancelled = False

    def cancel_analysis(self):
        """取消图片分析"""
        self.analysis_cancelled = True
        if hasattr(self, 'loading_window') and self.loading_window.winfo_exists():
            self.loading_window.destroy()
        messagebox.showinfo("已取消", "图片分析已取消")

    def _analyze_images_worker(self, image_paths):
        """后台线程中分析图片"""
        self.all_images_info = []

        for i, path in enumerate(image_paths):
            # 检查是否被取消
            if self.analysis_cancelled:
                break

            try:
                # 更新当前处理的文件
                self.current_analyzing_file = os.path.basename(path)

                # 在分析阶段使用预览模式以提高速度
                with self.open_image_file(path, preview_mode=True) as img:
                    dpi = img.info.get('dpi', (72, 72))[0]

                    # 获取真实尺寸（考虑预览模式的尺寸调整）
                    if 'original_size' in img.info:
                        # 如果有原始尺寸信息，使用它
                        width, height = img.info['original_size']
                    else:
                        width, height = self.get_oriented_size(img)

                    self.all_images_info.append({
                        'path': path,
                        'relative_path': None,  # 暂不计算相对路径以节省时间
                        'dpi': dpi,
                        'width': width,
                        'height': height
                    })

                # 更新进度
                self.analysis_progress = i + 1

            except Exception as e:
                print(f"无法分析图片 {path}: {e}")
                self.analysis_progress = i + 1
                continue

        # 标记分析完成
        self.analysis_complete = True

    def check_analysis_progress(self):
        """检查分析进度并更新UI"""
        if hasattr(self, 'loading_window') and self.loading_window.winfo_exists():
            # 更新进度条
            self.loading_progress['value'] = self.analysis_progress

            # 更新当前文件显示
            if self.current_analyzing_file:
                self.current_file_label.config(
                    text=f"正在处理: {self.current_analyzing_file}"
                )

            # 检查是否完成或取消
            if self.analysis_complete or self.analysis_cancelled:
                if hasattr(self, 'loading_window') and self.loading_window.winfo_exists():
                    self.loading_window.destroy()
                if self.analysis_complete and not self.analysis_cancelled:
                    self.finish_analysis()
            else:
                # 继续检查
                self.root.after(100, self.check_analysis_progress)

    def finish_analysis(self):
        """完成分析后的处理"""
        try:
            if not self.all_images_info:
                messagebox.showwarning("警告", "没有成功分析任何图片文件")
                return

            # 获取第一张图片的信息
            first_info = self.all_images_info[0]
            with self.open_image_file(first_info['path'], preview_mode=True) as first_image:
                self.original_width, self.original_height = self.get_oriented_size(first_image)
                self.original_dpi = first_image.info.get('dpi', (72, 72))[0]
                self.last_used_dpi = float(self.original_dpi)

            # 获取批量图片的统一性分析结果
            dpi_value, uniform_width, uniform_height, uniform_dpi, uniform_size = self.check_images_uniformity()

            # 更新UI显示
            self.update_ui_after_analysis(dpi_value, uniform_width, uniform_height, uniform_dpi, uniform_size)

            messagebox.showinfo("完成", f"成功分析了 {len(self.all_images_info)} 个图片文件")

        except Exception as e:
            messagebox.showerror("错误", f"完成分析时发生错误:\n{str(e)}")

    def update_ui_after_analysis(self, dpi_value, uniform_width, uniform_height, uniform_dpi, uniform_size):
        """分析完成后更新UI"""
        # 根据图片尺寸统一性控制保持比例功能
        if uniform_size or len(self.selected_files) == 1:
            self.maintain_ratio.set(True)
            if self.size_enabled.get():
                self.ratio_checkbox.configure(state="normal")
        else:
            self.maintain_ratio.set(False)
            self.ratio_checkbox.configure(state="disabled")

        # 更新DPI显示
        if uniform_dpi or len(self.selected_files) == 1:
            self.dpi_var.set(str(int(dpi_value)))
        else:
            self.dpi_var.set("")

        # 更新原始尺寸标签显示
        if uniform_size:
            self.original_size_label.configure(
                text=f"原始尺寸: {uniform_width} × {uniform_height} 像素"
            )
            if self.unit_var.get() == "pixel":
                self.width_var.set(str(uniform_width))
                self.height_var.set(str(uniform_height))
            else:
                current_dpi = float(self.dpi_var.get()) if self.dpi_var.get() else 72.0
                unit = self.unit_var.get()
                if unit == "cm":
                    width_cm = (uniform_width / current_dpi) * 2.54
                    height_cm = (uniform_height / current_dpi) * 2.54
                    self.width_var.set(f"{width_cm:.2f}")
                    self.height_var.set(f"{height_cm:.2f}")
                elif unit == "inch":
                    width_inch = uniform_width / current_dpi
                    height_inch = uniform_height / current_dpi
                    self.width_var.set(f"{width_inch:.2f}")
                    self.height_var.set(f"{height_inch:.2f}")
        else:
            # 如果尺寸不统一，显示提示文本
            self.original_size_label.configure(
                text=f"原始尺寸: {len(self.selected_files)} 个文件的尺寸不同"
            )

        # 启用相关控件
        self.size_checkbox.configure(state="normal")
        self.dpi_checkbox.configure(state="normal")

        # 更新预览显示
        self.update_size_preview()

    def get_oriented_size(self, img):
        """根据EXIF方向返回正确的图片尺寸"""
        width, height = img.size

        try:
            # 查找EXIF方向标签
            orientation = None
            if hasattr(img, '_getexif') and img._getexif():
                exif = img._getexif()
                # 查找orientation标签
                for tag, tag_value in ExifTags.TAGS.items():
                    if tag_value == 'Orientation':
                        if tag in exif:
                            orientation = exif[tag]
                            break

            # 根据方向调整宽度和高度
            # 方向值5-8表示图片需要旋转90°或270°
            if orientation in [5, 6, 7, 8]:
                # 交换宽度和高度
                width, height = height, width
        except Exception:
            # 如果无法读取EXIF或出现其他错误，使用原始尺寸
            pass

        return width, height

    def check_images_uniformity(self):
        """检查所有图片的DPI和尺寸是否统一"""
        if not self.all_images_info:
            return None, None, None, None, None

        first = self.all_images_info[0]
        uniform_dpi = all(img['dpi'] == first['dpi'] for img in self.all_images_info)
        uniform_size = all(img['width'] == first['width'] and
                           img['height'] == first['height']
                           for img in self.all_images_info)

        # 如果需要，在检查完图片均匀性后调整窗口高度
        self.adjust_window_height()

        return (first['dpi'] if uniform_dpi else None,
                first['width'] if uniform_size else None,
                first['height'] if uniform_size else None,
                uniform_dpi,
                uniform_size)
